<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Spark • Environment Mapping</title>
  <style>
    body {
      margin: 0;
    }

    label {
      font-family: sans-serif;
      font-size: 20px;
      position: absolute;
      color: white;
      cursor: pointer;
      padding: 10px;
      border-radius: 10px;
      display: block;
      width: 100px;
      left: calc(50% - 50px);
      top: 10px;
      text-align: center;
      background-color: black;
    }
  </style>
</head>

<body>
  <label><input type="checkbox" onchange="toggleMetal(this)" autocomplete="off"> Plastic</label>
  <script type="importmap">
    {
      "imports": {
        "three": "/examples/js/vendor/three/build/three.module.js",
        "three/addons/": "/examples/js/vendor/three/examples/jsm/",
        "@sparkjsdev/spark": "/dist/spark.module.js"
      }
    }
  </script>
  <script type="module">
    import * as THREE from "three";
    import { SplatMesh, SparkRenderer, PackedSplats } from "@sparkjsdev/spark";
    import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
    import { getAssetFileURL } from "/examples/js/get-asset-url.js";

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.y = 0.5;
    const renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(new THREE.Color(0x1b2037), 1.0);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    window.addEventListener('resize', onWindowResize, false);
    function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    }

    // Explicitly create a SparkRenderer to render environment maps
    const spark = new SparkRenderer({ renderer });
    scene.add(spark);

    const splatURL = await getAssetFileURL("fireplace.spz");
    const packedSplats = new PackedSplats({ url: splatURL });
    const background = new SplatMesh({ packedSplats });
    background.quaternion.set(1, 0, 0, 0);
    background.position.set(0.5, 0, -1);
    background.scale.setScalar(0.5);
    scene.add(background);

    const background2 = new SplatMesh({ packedSplats });
    background2.quaternion.set(1, 0, 0, 0);
    background2.rotation.y = Math.PI;
    background2.position.set(-0.5, 0, 0.0);
    background2.scale.setScalar(0.5);
    scene.add(background2);

    // Make sure background is loaded before rendering env map
    await background.initialized;
    await background2.initialized;

    // Add rubber duck
    const gltfLoader = new GLTFLoader();
    const modelURL = await getAssetFileURL('rubberduck.glb');
    const gltf = await gltfLoader.loadAsync(modelURL);
    const duck = gltf.scene;
    duck.position.set(0, 0.45, -0.4);
    scene.add(duck);

    let lastTime;
    let renderedEnvMap = false;
    renderer.setAnimationLoop(function animate(time) {
      const deltaTime = time - (lastTime || time);
      lastTime = time;
      renderer.render(scene, camera);
      duck.rotation.y += deltaTime / 2500;

      // Make sure we only launch async renderEnvMap once
      if (!renderedEnvMap) {
        renderedEnvMap = true;
        spark.renderEnvMap({
          scene,
          // World center to render from
          worldCenter: duck.position,
          // Hide the duck so we don't obscure the environment
          hideObjects: [duck],
          // Not needed in normal use, guards against "first render" issues
          update: true,
        })
          .then((envMap) => {
            for (let obj of duck.children) {
              // Set some reflectivity in the materials of the duck
              obj.material.envMap = envMap;
              obj.material.original_color = obj.material.color.clone();
              obj.material.metalness = 1.0;
              obj.material.roughness = 0.02;
            }
          });
      }
    });

    // Toggles between normal duck and metal duck
    window.toggleMetal = function toggleMetal(el) {
      const metal = el.checked;
      for (let obj of duck.children) {
        obj.material.metalness = metal ? 0.0 : 1.0;
        obj.material.roughness = metal ? 0.2 : 0.02;
      }
    }
  </script>
</body>

</html>
